"""用栈来判断字符串是否为回文（忽略大小写、空格）"""

class Stack:
    def __init__(self):
        #属性是一个列表 存储栈中的元素
        self.items = []

    #往栈中压入一个元素 实际效果是往items这个列表的尾部添加一个元素
    def push(self, item):
        self.items.append(item)

    #栈弹出一个元素(要遵循后进先出的思想) 实际效果是items这个列表的最后一个元素被弹出(pop)
    def pop(self):
        #和push不同，pop方法一定要先判断"栈"中是否有元素 栈不为空 再弹出元素 栈为空 则返回None
        if not self.is_empty():
            #在 Python 中，list.pop() 是列表的内置方法，用于移除并返回列表中指定索引位置的元素。
            # 如果不指定索引，默认移除并返回列表的最后一个元素。
            #此处pop方法，移除列表的最后一个元素(该元素是最新的数据)，体现了栈的后进先出
            return self.items.pop()
        return None

    #栈的判空 直接用items列表的len来判断
    def is_empty(self):
        return len(self.items) == 0

def is_palindrome(s):
    """栈判断字符串是否为回文（忽略大小写、空格）"""
    s = s.lower().replace(" ", "")  # 统一小写并去掉空格
    stack = Stack()
    # 前半部分入栈 方便与后半部分做对比 以验证是否是回文
    mid = len(s) // 2
    #时刻注意 range方法不包含最后一个元素(这里就是mid下标)
    for i in range(mid):
        stack.push(s[i])
    # 若长度为奇数 跳过中间字符 比如：abcdcba 跳过d 直接从最后的cba开始比较
    start = mid if len(s) % 2 == 0 else mid + 1
    # 后半部分与栈顶比较  range第二个参数是len(s),不用-1也没事，因为range方法的end参数不会取到
    for i in range(start, len(s)):
        if stack.pop() != s[i]:
            return False
    #即使前面都对比成功了（后半部分的元素依次和栈顶元素对比），最后这里还要考虑 栈中的元素是否都弹出了 如果栈最后还有剩余 说明也不是回文
    return stack.is_empty()

# 测试
if __name__ == "__main__":
    print(is_palindrome("A man a plan a canal Panama"))  # 输出: True
    print(is_palindrome("hello"))                        # 输出: False
    print(is_palindrome("level"))                        # 输出: True